package threadpool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * ThreadPoolExecutor的线程的变化过程：
 * 当主线程中调用execute接口提交执行任务时：
 * 则执行以下步骤：
 * 注意：线程池初始时，是空的。
 * <p>
 * 如果当前线程数<corePoolSize，如果是则创建新的线程执行该任务
 * 如果当前线程数>=corePoolSize，则将任务存入任务队列
 * 如果阻塞队列已满，且当前线程数<maximumPoolSize，则新建线程执行该任务。
 * 如果阻塞队列已满，且当前线程数>=maximumPoolSize，则触发拒绝策略
 * 其中，非核心线程受空闲时间影响，  当其线程空闲时间达到指定的空闲时间时，将会被关闭这个线程，减少系统开销。  核心线程不受此影响
 * <p>
 * <p>
 * 注意点：
 * 线程池初始化时，是空的。
 * 如果阻塞队列已满，且当前线程数<maximumPoolSize，则新建线程执行该任务。而不是新建线程，从阻塞队列里take任务来执行，所以这里并不是先来先执行的。
 * <p>
 * <p>
 * <p>
 * <p>
 * 5. ThreadPoolExecutor的扩展
 * 我们看ThreadPoolExecutor的源码发现如下三个函数的实现为空且是protected。明显用于子类实现的。
 * <p>
 * protected void beforeExecute(Thread t, Runnable r) { }
 * protected void afterExecute(Runnable r, Throwable t) { }
 * protected void terminated() { }
 * 在执行任务的线程中将调用beforeExecute和afterExecute等方法，在这些方法中还可以添加日志、计时、监视或者统计信息收集的功能。
 * 无论任务是从run中正常返回，还是抛出一个异常而返回，afterExecute都会被调用。如果任务在完成后带有一个Error，那么就不会调用afterExecute。
 * 如果beforeExecute抛出一个RuntimeException，那么任务将不被执行，并且afterExecute也不会被调用。
 * 在线程池完成关闭时调用terminated，也就是在所有任务都已经完成并且所有工作者线程也已经关闭后，terminated可以用来释放Executor在其生命周期里分配的各种资源，
 * 此外还可以执行发送通知、记录日志或者收集finalize统计等操作。
 * 即我们可以子类来继承ThreadPoolExecutor来定制化一些功能。
 */
public class T06_ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,
                4,
                60L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4),
                Executors.defaultThreadFactory(),
//                new ThreadPoolExecutor.DiscardOldestPolicy() //丢弃排队时间最长的任务，将新任务扔到任务队列里
//                new ThreadPoolExecutor.AbortPolicy() // 抛出异常
                new ThreadPoolExecutor.CallerRunsPolicy() //调用所在线程执行这个任务
//                new ThreadPoolExecutor.DiscardPolicy() //不抛出异常，也不接收新任务，让该任务凭空消失
        );


        //测试DiscardOldestPolicy策略
//        for (int i = 0; i < 8; i++) {
//        threadPoolExecutor.execute(new Task("i"+i));
//        }
//        System.out.println(threadPoolExecutor.getQueue());
//        threadPoolExecutor.execute(()-> System.out.println(Thread.currentThread().getName()));
//        System.out.println(threadPoolExecutor.getQueue());

        for (int i = 0; i < 4; i++) {
            threadPoolExecutor.execute(new Task("i" + i));
        }
        System.out.println(threadPoolExecutor);

    }


    static class Task implements Runnable {
        public String name;

        public Task(String name) {
            this.name = name;
        }

        @Override
        public void run() {
//            System.out.println(Thread.currentThread().getName());
            while (true) {

            }
        }

        public void printThreadName() {
            System.out.println(Thread.currentThread().getName());
        }

        @Override
        public String toString() {
            return "Task{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
}
